using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MT5Trade.Models
{
    /// <summary>
    /// 基于泊松过程的智能重试执行器
    /// 使用泊松分布模型优化重试间隔，提高系统鲁棒性
    /// </summary>
    public class PoissonRetryExecutor
    {
        #region 常量定义

        // 默认参数
        public const double DEFAULT_LAMBDA = 1.0;           // 默认泊松参数
        public const int DEFAULT_MAX_RETRIES = 5;           // 默认最大重试次数
        public const int DEFAULT_BASE_DELAY_MS = 1000;      // 基础延迟(毫秒)
        public const int MAX_DELAY_MS = 30000;              // 最大延迟(毫秒)
        
        // 自适应调整参数
        public const double SUCCESS_RATE_THRESHOLD = 0.7;   // 成功率阈值
        public const double LAMBDA_INCREMENT = 0.1;         // λ增量
        public const double LAMBDA_MIN = 0.1;               // 最小λ值
        public const double LAMBDA_MAX = 5.0;               // 最大λ值

        #endregion

        #region 私有字段

        private readonly IRandomProvider _randomProvider;
        private readonly ConcurrentDictionary<string, OperationExecutionStatistics> _operationStats;
        private double _lambda;
        private readonly object _lockObj = new object();

        #endregion

        #region 构造函数

        /// <summary>
        /// 初始化泊松重试执行器
        /// </summary>
        /// <param name="lambda">泊松分布参数</param>
        /// <param name="randomProvider">随机数提供器</param>
        public PoissonRetryExecutor(double lambda = DEFAULT_LAMBDA, IRandomProvider randomProvider = null)
        {
            _lambda = Math.Max(LAMBDA_MIN, Math.Min(LAMBDA_MAX, lambda));
            _randomProvider = randomProvider ?? new DeterministicRandomProvider();
            _operationStats = new ConcurrentDictionary<string, OperationExecutionStatistics>();
        }

        #endregion

        #region 核心重试方法

        /// <summary>
        /// 执行带重试的操作
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="operation">要执行的操作</param>
        /// <param name="operationName">操作名称（用于统计）</param>
        /// <param name="maxRetries">最大重试次数</param>
        /// <param name="shouldRetry">判断是否应该重试的函数</param>
        /// <returns>操作结果</returns>
        public async Task<T> ExecuteWithRetryAsync<T>(
            Func<Task<T>> operation,
            string operationName,
            int maxRetries = DEFAULT_MAX_RETRIES,
            Func<Exception, bool> shouldRetry = null)
        {
            if (operation == null)
                throw new ArgumentNullException(nameof(operation));

            var stats = GetOrCreateStatistics(operationName);
            var adaptiveParams = CalculateAdaptiveParameters(stats, maxRetries);
            
            Exception lastException = null;
            int attempt = 0;

            while (attempt <= adaptiveParams.MaxRetries)
            {
                try
                {
                    // 执行操作
                    var result = await operation().ConfigureAwait(false);
                    
                    // 记录成功
                    RecordSuccess(stats);
                    
                    return result;
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    
                    // 检查是否应该重试
                    if (shouldRetry != null && !shouldRetry(ex))
                    {
                        RecordFailure(stats);
                        throw;
                    }
                    
                    // 检查是否还有重试机会
                    if (attempt >= adaptiveParams.MaxRetries)
                    {
                        RecordFailure(stats);
                        throw new AggregateException($"操作 {operationName} 在 {attempt} 次尝试后失败", lastException);
                    }
                    
                    // 计算延迟并等待
                    var delay = CalculatePoissonDelay(attempt, adaptiveParams.Lambda);
                    await Task.Delay(delay).ConfigureAwait(false);
                    
                    attempt++;
                }
            }

            throw new AggregateException($"操作 {operationName} 达到最大重试次数", lastException);
        }

        /// <summary>
        /// 同步版本的重试执行
        /// </summary>
        public T ExecuteWithRetry<T>(
            Func<T> operation,
            string operationName,
            int maxRetries = DEFAULT_MAX_RETRIES,
            Func<Exception, bool> shouldRetry = null)
        {
            var asyncOperation = new Func<Task<T>>(() => Task.FromResult(operation()));
            return ExecuteWithRetryAsync(asyncOperation, operationName, maxRetries, shouldRetry).Result;
        }

        #endregion

        #region 泊松延迟计算

        /// <summary>
        /// 计算基于泊松过程的重试延迟
        /// </summary>
        /// <param name="attemptNumber">尝试次数</param>
        /// <param name="lambda">泊松参数</param>
        /// <returns>延迟时间（毫秒）</returns>
        public TimeSpan CalculatePoissonDelay(int attemptNumber, double lambda)
        {
            // 使用指数分布生成到达间隔
            // 泊松过程的到达间隔服从参数为λ的指数分布
            double u = GetDeterministicValue(attemptNumber);
            
            // 逆变换方法：X = -ln(U) / λ
            double exponentialDelay = -Math.Log(1 - u) / lambda;
            
            // 应用自适应因子（随尝试次数增加）
            double adaptiveFactor = Math.Pow(1.5, attemptNumber);
            
            // 计算最终延迟（毫秒）
            int delayMs = (int)(DEFAULT_BASE_DELAY_MS * exponentialDelay * adaptiveFactor);
            
            // 确保不超过最大延迟
            delayMs = Math.Min(delayMs, MAX_DELAY_MS);
            
            return TimeSpan.FromMilliseconds(delayMs);
        }

        /// <summary>
        /// 获取确定性的伪随机值
        /// </summary>
        private double GetDeterministicValue(int attemptNumber)
        {
            // 使用确定性随机数生成器
            double baseValue = _randomProvider.NextDouble();
            
            // 加入尝试次数的影响，确保每次尝试的值不同
            double adjustment = (attemptNumber * 0.1) % 1.0;
            double value = (baseValue + adjustment) % 1.0;
            
            // 确保值在(0,1)范围内
            return Math.Max(0.01, Math.Min(0.99, value));
        }

        #endregion

        #region 自适应参数调整

        /// <summary>
        /// 计算自适应参数
        /// </summary>
        private AdaptiveParameters CalculateAdaptiveParameters(OperationExecutionStatistics stats, int baseMaxRetries)
        {
            var parameters = new AdaptiveParameters
            {
                Lambda = _lambda,
                MaxRetries = baseMaxRetries
            };

            // 根据历史成功率调整
            if (stats.TotalAttempts > 10)
            {
                double successRate = stats.SuccessRate;
                
                if (successRate < SUCCESS_RATE_THRESHOLD)
                {
                    // 成功率低，增加λ（更长的延迟）和重试次数
                    parameters.Lambda = Math.Min(LAMBDA_MAX, _lambda + LAMBDA_INCREMENT);
                    parameters.MaxRetries = Math.Min(baseMaxRetries + 2, 10);
                }
                else if (successRate > 0.9)
                {
                    // 成功率高，减少λ（更短的延迟）
                    parameters.Lambda = Math.Max(LAMBDA_MIN, _lambda - LAMBDA_INCREMENT);
                    parameters.MaxRetries = Math.Max(baseMaxRetries - 1, 1);
                }
                
                // 更新全局λ值
                lock (_lockObj)
                {
                    _lambda = parameters.Lambda;
                }
            }

            return parameters;
        }

        /// <summary>
        /// 获取或创建操作统计
        /// </summary>
        private OperationExecutionStatistics GetOrCreateStatistics(string operationName)
        {
            return _operationStats.GetOrAdd(operationName, _ => new OperationExecutionStatistics
            {
                OperationName = operationName,
                CreatedAt = DateTime.UtcNow
            });
        }

        /// <summary>
        /// 记录成功
        /// </summary>
        private void RecordSuccess(OperationExecutionStatistics stats)
        {
            lock (stats)
            {
                stats.SuccessCount++;
                stats.TotalAttempts++;
                stats.LastSuccessAt = DateTime.UtcNow;
                
                // 更新连续失败计数
                stats.ConsecutiveFailures = 0;
            }
        }

        /// <summary>
        /// 记录失败
        /// </summary>
        private void RecordFailure(OperationExecutionStatistics stats)
        {
            lock (stats)
            {
                stats.FailureCount++;
                stats.TotalAttempts++;
                stats.LastFailureAt = DateTime.UtcNow;
                stats.ConsecutiveFailures++;
            }
        }

        #endregion

        #region 统计和监控

        /// <summary>
        /// 获取操作统计信息
        /// </summary>
        public OperationExecutionStatistics GetStatistics(string operationName)
        {
            return _operationStats.TryGetValue(operationName, out var stats) ? stats : null;
        }

        /// <summary>
        /// 获取所有操作统计
        /// </summary>
        public Dictionary<string, OperationExecutionStatistics> GetAllStatistics()
        {
            return new Dictionary<string, OperationExecutionStatistics>(_operationStats);
        }

        /// <summary>
        /// 重置统计信息
        /// </summary>
        public void ResetStatistics(string operationName = null)
        {
            if (operationName != null)
            {
                _operationStats.TryRemove(operationName, out _);
            }
            else
            {
                _operationStats.Clear();
            }
        }

        /// <summary>
        /// 获取当前Lambda值
        /// </summary>
        public double GetCurrentLambda()
        {
            lock (_lockObj)
            {
                return _lambda;
            }
        }

        #endregion

        #region 熔断器集成

        /// <summary>
        /// 检查是否应该触发熔断
        /// </summary>
        public bool ShouldTriggerCircuitBreaker(string operationName)
        {
            var stats = GetStatistics(operationName);
            if (stats == null)
                return false;
            
            // 连续失败超过阈值触发熔断
            const int CIRCUIT_BREAKER_THRESHOLD = 5;
            return stats.ConsecutiveFailures >= CIRCUIT_BREAKER_THRESHOLD;
        }

        /// <summary>
        /// 重置熔断器状态
        /// </summary>
        public void ResetCircuitBreaker(string operationName)
        {
            var stats = GetStatistics(operationName);
            if (stats != null)
            {
                lock (stats)
                {
                    stats.ConsecutiveFailures = 0;
                }
            }
        }

        #endregion
    }

    #region 辅助类定义

    /// <summary>
    /// 操作执行统计信息
    /// </summary>
    public class OperationExecutionStatistics
    {
        public string OperationName { get; set; }
        public int TotalAttempts { get; set; }
        public int SuccessCount { get; set; }
        public int FailureCount { get; set; }
        public int ConsecutiveFailures { get; set; }
        public DateTime CreatedAt { get; set; }
        public DateTime? LastSuccessAt { get; set; }
        public DateTime? LastFailureAt { get; set; }
        
        /// <summary>
        /// 成功率
        /// </summary>
        public double SuccessRate => TotalAttempts > 0 ? (double)SuccessCount / TotalAttempts : 0;
        
        /// <summary>
        /// 平均成功间隔（秒）
        /// </summary>
        public double AverageSuccessInterval
        {
            get
            {
                if (SuccessCount <= 1 || !LastSuccessAt.HasValue)
                    return 0;
                
                var totalTime = (LastSuccessAt.Value - CreatedAt).TotalSeconds;
                return totalTime / SuccessCount;
            }
        }
    }

    /// <summary>
    /// 自适应参数
    /// </summary>
    internal class AdaptiveParameters
    {
        public double Lambda { get; set; }
        public int MaxRetries { get; set; }
    }

    #endregion
}